"""电影应用API视图模块

定义了处理电影相关HTTP请求的视图类，包括电影列表、详情、用户偏好设置和推荐功能。
"""

import os
import uuid
from typing import Any, Optional

from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework import generics, status
from rest_framework.decorators import permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

from api_auth.permissions import CustomDjangoModelPermissions
from movies.models import Movie, UserMoviePreferences
from movies.services import add_preference, add_watch_history
from movies.tasks import process_file
from recommendations.services import Item, UserPreferences, get_recommendations

from .serializers import (
    AddPreferenceSerializer,
    AddToWatchHistorySerializer,
    GeneralFileUploadSerializer,
    MovieSerializer,
)
from .services import user_preferences, user_watch_history


@extend_schema(
    summary="获取所有电影",
    description="返回系统中可用电影的分页列表。对于大型数据集，请使用过滤器和分页参数。",
    responses={
        200: MovieSerializer(many=True),  # 成功时的响应模式
    },
    parameters=[
        OpenApiParameter("page", int, description="分页的页码"),
        OpenApiParameter("size", int, description="分页的页面大小"),
    ],
    methods=["GET"],  # 显式记录GET方法
)
class MovieListCreateAPIView(generics.ListCreateAPIView):
    """电影列表和创建API视图类"""

    permission_classes = (IsAuthenticated, CustomDjangoModelPermissions)  # 权限控制
    queryset = Movie.objects.all().order_by("id")  # 查询所有电影并按ID排序
    serializer_class = MovieSerializer  # 使用电影序列化器


class MovieDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    """电影详情API视图类"""

    permission_classes = [IsAuthenticated, CustomDjangoModelPermissions]  # 权限控制
    queryset = Movie.objects.all()  # 查询所有电影
    serializer_class = MovieSerializer  # 使用电影序列化器


class UserPreferencesView(APIView):
    """用户偏好设置API视图类"""

    permission_classes = [IsAuthenticated]  # 权限控制

    def post(self, request: Request, user_id: int) -> Response:
        """
        添加用户偏好设置

        Args:
            request: HTTP请求对象
            user_id: 用户ID

        Returns:
            Response: 响应对象
        """
        serializer = AddPreferenceSerializer(data=request.data)
        if serializer.is_valid():
            add_preference(user_id, serializer.validated_data["new_preferences"])
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def get(self, request: Request, user_id: int) -> Response:
        """
        获取用户偏好设置

        Args:
            request: HTTP请求对象
            user_id: 用户ID

        Returns:
            Response: 包含用户偏好设置的响应对象
        """
        data = user_preferences(user_id)
        return Response(data)


@permission_classes([IsAuthenticated])
class WatchHistoryView(APIView):
    """观看历史API视图类"""

    permission_classes = [IsAuthenticated]  # 权限控制

    def get(self, request: Request, user_id: int) -> Response:
        """
        获取用户观看历史

        Args:
            request: HTTP请求对象
            user_id: 用户ID

        Returns:
            Response: 包含用户观看历史的响应对象
        """
        data = user_watch_history(user_id)
        return Response(data)

    def post(self, request: Request, user_id: int) -> Response:
        """
        添加电影到用户观看历史

        Args:
            request: HTTP请求对象
            user_id: 用户ID

        Returns:
            Response: 响应对象
        """
        serializer = AddToWatchHistorySerializer(data=request.data)
        if serializer.is_valid():
            add_watch_history(
                user_id,
                serializer.validated_data["id"],
            )
            return Response(
                {"message": "Movie added to watch history."},
                status=status.HTTP_201_CREATED,
            )
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class GeneralUploadView(APIView):
    """通用文件上传API视图类"""

    permission_classes = [IsAuthenticated]  # 权限控制

    def post(self, request, *args: Any, **kwargs: Any) -> Response:
        """
        处理文件上传请求

        Args:
            request: HTTP请求对象
            *args: 位置参数
            **kwargs: 关键字参数

        Returns:
            Response: 响应对象
        """
        serializer = GeneralFileUploadSerializer(data=request.data)
        if serializer.is_valid():
            uploaded_file = serializer.validated_data["file"]
            file_type = uploaded_file.content_type

            # 提取文件扩展名
            file_extension = os.path.splitext(uploaded_file.name)[1]
            # 使用UUID生成唯一文件名
            unique_file_name = f"{uuid.uuid4()}{file_extension}"

            # 将文件保存到默认存储中
            file_name = default_storage.save(
                unique_file_name, ContentFile(uploaded_file.read())
            )

            process_file.delay(file_name, file_type)

            return Response(
                {"message": f"Job enqueued for processing."},
                status=status.HTTP_202_ACCEPTED,
            )
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class MovieRecommendationAPIView(APIView):
    """电影推荐API视图类"""

    def get(self, request):
        """
        获取电影推荐

        Args:
            request: HTTP请求对象

        Returns:
            Response: 包含推荐电影的响应对象
        """
        user_id = request.query_params.get("user_id")

        if not user_id:
            return self._response_error(
                detail="user_id query parameter is required.",
                status_code=status.HTTP_400_BAD_REQUEST,
            )

        user_preferences = self._get_user_preferences(user_id)
        if not user_preferences:
            return self._response_error(
                detail="User preferences not found.",
                status_code=status.HTTP_404_NOT_FOUND,
            )

        recommended_items = self._get_recommended_items(user_preferences)
        response_data = self._format_response(recommended_items)

        return Response(response_data, status=status.HTTP_200_OK)

    def _get_user_preferences(self, user_id: str) -> Optional[UserPreferences]:
        """
        从数据库中获取用户偏好设置并将其转换为UserPreferences Pydantic模型。

        Args:
            user_id: 要获取其偏好设置的用户ID。

        Returns:
            UserPreferences对象，包含用户的偏好设置；如果不存在偏好设置则返回None。
        """
        try:
            # 从数据库中获取用户偏好设置
            user_prefs = UserMoviePreferences.objects.get(user_id=user_id)

            # 提取相关的偏好设置
            genre = user_prefs.preferences.get("genre", [])
            director = user_prefs.preferences.get("director", [])
            actor = user_prefs.preferences.get("actor", [])
            year_range = user_prefs.preferences.get("year", [])

            # 处理年份范围（期望为列表）
            year_range_start, year_range_end = (
                (year_range[0], year_range[-1])
                if len(year_range) >= 2
                else (None, None)
            )

            # 构建偏好设置字典
            preferences_dict = {
                "genre": genre,
                "director": director,
                "actor": actor,
                "year_range_start": year_range_start,
                "year_range_end": year_range_end,
            }

            # 使用偏好设置字典实例化UserPreferences
            return UserPreferences(
                preferences=preferences_dict,
                watch_history=user_prefs.watch_history,  # 假设这在user_prefs中存在
            )
        except UserMoviePreferences.DoesNotExist:
            return None  # 如果未找到用户的偏好设置则返回None

    def _get_recommended_items(self, user_preferences: UserPreferences) -> list[Item]:
        """
        基于用户偏好设置生成推荐项目（在此为电影）列表。

        Args:
            user_preferences: 用户的偏好设置。

        Returns:
            推荐项目列表，以Item对象表示。
        """
        movies = Movie.objects.all()

        items = [
            Item(
                id=movie.id,
                attributes={
                    "name": movie.title,
                    "genre": movie.genres,
                    "director": movie.extra_data.get("directors", ""),
                    "year": movie.release_year,
                },
            )
            for movie in movies
        ]

        return get_recommendations(user_preferences=user_preferences, items=items)

    def _format_response(self, recommended_items: list[Item]) -> list[dict]:
        """
        将推荐项目格式化为响应友好的结构。

        Args:
            recommended_items: 表示推荐内容的Item对象列表。

        Returns:
            包含内容ID和名称的字典列表。
        """
        return [
            {"id": item.id, "title": item.attributes.get("name", "Unknown")}
            for item in recommended_items
        ]

    def _response_error(self, detail: str, status_code: int) -> Response:
        """
        构造错误响应。

        Args:
            detail: 包含在响应中的错误消息。
            status_code: 响应的HTTP状态码。

        Returns:
            包含错误消息和状态码的Response对象。
        """
        return Response({"detail": detail}, status=status_code)
